package frontend.visitor.symboltbl;

import exceptions.VisitInnerException;
import utils.Wrapper;

public class SymbolConstInitial {
    private final int dimension;
    private int initial_dim0;
    private int[] initial_dim1;
    private int[][] initial_dim2;
    private final int[] dimensionLen = new int[2];
    public SymbolConstInitial(int initial) {
        this.dimension = 0;
        this.initial_dim0 = initial;
    }
    public SymbolConstInitial(int[] initial, int len) {
        if (len < 0) throw new VisitInnerException();
        this.dimension = 1;
        this.dimensionLen[0] = len;
        this.initial_dim1 = new int[len];
        for (int i = 0; i < len; i++) {
            if (i >= initial.length) break;
            this.initial_dim1[i] = initial[i];
        }
    }
    public SymbolConstInitial(int[][] initial, int len1, int len2) {
        if (len1 < 0 || len2 < 0) throw new VisitInnerException();
        this.dimension = 2;
        this.dimensionLen[0] = len1; this.dimensionLen[1] = len2;
        this.initial_dim2 = new int[len1][len2];
        for (int i = 0; i < len1; i++) {
            if (i >= initial.length) break;
            for (int j = 0; j < len2; j++) {
                if (j >= initial[i].length) break;
                this.initial_dim2[i][j] = initial[i][j];
            }
        }
    }
    public Integer getIntVal(Wrapper<Symbol.ErrorCase> upErrorCase, int... offsets) {
        upErrorCase.set(Symbol.ErrorCase.SUCCESS);
        if (offsets.length < dimension) {
            upErrorCase.set(Symbol.ErrorCase.OFFSETS_TOO_SHORT);
            return null;
        }
        else if (offsets.length > dimension) {
            upErrorCase.set(Symbol.ErrorCase.OFFSETS_TOO_LONG);
            return null;
        }
        switch (dimension) {
            case 0 -> {
                return initial_dim0;
            }
            case 1 -> {
                if (offsets[0] < 0 || offsets[0] >= dimensionLen[0]) {
                    upErrorCase.set(Symbol.ErrorCase.CROSS_THE_BORDER);
                    return null;
                }
                return initial_dim1[offsets[0]];
            }
            case 2 -> {
                if (offsets[0] < 0 || offsets[0] >= dimensionLen[0] ||
                    offsets[1] < 0 || offsets[1] >= dimensionLen[1]) {
                    upErrorCase.set(Symbol.ErrorCase.CROSS_THE_BORDER);
                    return null;
                }
                return initial_dim2[offsets[0]][offsets[1]];
            }
            default -> {
                return null;
            }
        }
    }

    public int getDimension() {
        return dimension;
    }
}
